-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[KEP-0009] feat: add expression based assertions #576
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, but needs a few changes.
pkg/test/utils/kubernetes.go
Outdated
variables[resourceRef.Id] = referencedResource.Object | ||
} | ||
|
||
env, err := cel.NewEnv() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling cel.NewEnv()
may not be enough, you probably want to enable a couple of options/libs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eddycharly any hints on what might be useful? 🤔
0fe748e
to
a85752a
Compare
Thanks for the quick review @porridge . I'll add the tests tomorrow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks much better, but some more changes are needed. 🙏🏻
Please see inline.
7044f54
to
a7122a6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there!
Just a bunch of nitpicks for messages and identifier names, and one issue in the test..
...gration_test_data/assert_expressions/check_expression_for_ephemeral_namespace/01-assert.yaml
Outdated
Show resolved
Hide resolved
...gration_test_data/assert_expressions/check_expression_for_ephemeral_namespace/00-create.yaml
Outdated
Show resolved
Hide resolved
pkg/test/utils/kubernetes.go
Outdated
variables[resourceRef.Id] = referencedResource.Object | ||
} | ||
|
||
env, err := cel.NewEnv() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eddycharly any hints on what might be useful? 🤔
1752619
to
32bcb9c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more things.
...gration_test_data/assert_expressions/check_expression_for_ephemeral_namespace/01-assert.yaml
Outdated
Show resolved
Hide resolved
This PR adds CEL-expression based assertions to `TestAsserts`. See https://github.com/kudobuilder/kuttl/blob/main/keps/0009-expression-based-assertions.md for more details. Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
…re present Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
…pace Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
dd2131a
to
dd85a98
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM now, just the debugging leftovers need to go :-)
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Signed-off-by: Kumar Mallikarjuna <[email protected]>
Shouldn't you verify that the program return type is a boolean ? Something like:
|
return nil, fmt.Errorf("failed to load resource reference(s): %w", errors.Join(errs...)) | ||
} | ||
|
||
env, err := cel.NewEnv() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you extending the env somewhere ? Looks like you will want to register a bunch of CEL libs to enable features.
} | ||
|
||
for _, resourceRef := range resourceRefs { | ||
env, err = env.Extend(cel.Variable(resourceRef.Ref, cel.DynType)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to use a type provider instead of DynType
.
} | ||
|
||
func evaluateExpression(expr string, | ||
programs map[string]cel.Program, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why create a map to lookup the program corresponding to an expression ? 🤔
@@ -157,6 +157,11 @@ type TestAssert struct { | |||
Collectors []*TestCollector `json:"collectors,omitempty"` | |||
// Commands is a set of commands to be run as assertions for the current step | |||
Commands []TestAssertCommand `json:"commands,omitempty"` | |||
|
|||
ResourceRefs []TestResourceRef `json:"resourceRefs,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should consider two TestResourceRef
with the same id an error.
var anyExprErrors, allExprErrors []error | ||
for _, expr := range assertAny { | ||
if err := evaluateExpression(expr.CELExpression, programs, variables); err != nil { | ||
anyExprErrors = append(anyExprErrors, err) | ||
} | ||
} | ||
|
||
for _, expr := range assertAll { | ||
if err := evaluateExpression(expr.CELExpression, programs, variables); err != nil { | ||
allExprErrors = append(allExprErrors, err) | ||
} | ||
} | ||
|
||
if len(assertAny) != 0 && len(anyExprErrors) == len(assertAny) { | ||
errs = append(errs, fmt.Errorf("no expression evaluated to true: %w", errors.Join(anyExprErrors...))) | ||
} | ||
|
||
if len(allExprErrors) > 0 { | ||
errs = append(errs, fmt.Errorf("not all assertAll expressions evaluated to true: %w", errors.Join(allExprErrors...))) | ||
} | ||
|
||
return errs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would make sense to return early here instead of evaluating all expressions before making a decision.
variables := make(map[string]interface{}) | ||
for _, resourceRef := range s.Assert.ResourceRefs { | ||
if resourceRef.Namespace == "" { | ||
resourceRef.Namespace = namespace | ||
} | ||
namespacedName, referencedResource := resourceRef.BuildResourceReference() | ||
if err := client.Get(context.TODO(), namespacedName, referencedResource); err != nil { | ||
return []error{fmt.Errorf("failed to get referenced resource '%v': %w", namespacedName, err)} | ||
} | ||
|
||
variables[resourceRef.Ref] = referencedResource.Object | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be lazy loaded.
What this PR does / why we need it:
This PR adds CEL-expression based assertions to
TestAsserts
. See https://github.com/kudobuilder/kuttl/blob/main/keps/0009-expression-based-assertions.md for more details.Fixes #562